#ifndef _WX_WXZSTREAM_H__
#define _WX_WXZSTREAM_H__

#include "wx/defs.h"

#if wxUSE_ZLIB && wxUSE_STREAMS

#include "wx/stream.h"

// Compression level
enum {
  wxZ_DEFAULT_COMPRESSION = -1,
  wxZ_NO_COMPRESSION = 0,
  wxZ_BEST_SPEED = 1,
  wxZ_BEST_COMPRESSION = 9
};

// Flags
enum {
  wxZLIB_NO_HEADER = 0,    // raw deflate stream, no header or checksum
  wxZLIB_ZLIB = 1,         // zlib header and checksum
  wxZLIB_GZIP = 2,         // gzip header and checksum, requires zlib 1.2.1+
  wxZLIB_AUTO = 3          // autodetect header zlib or gzip
};

class wxZlibInputStream: public wxFilterInputStream {
  public:
    wxZlibInputStream( wxInputStream& stream, int flags = wxZLIB_AUTO );
    wxZlibInputStream( wxInputStream *stream, int flags = wxZLIB_AUTO );
    virtual ~wxZlibInputStream();

    char Peek() { return wxInputStream::Peek(); }
    wxFileOffset GetLength() const { return wxInputStream::GetLength(); }

    static bool CanHandleGZip();

  protected:
    size_t OnSysRead( void *buffer, size_t size );
    wxFileOffset OnSysTell() const { return m_pos; }

  private:
    void Init( int flags );

  protected:
    size_t m_z_size;
    unsigned char *m_z_buffer;
    struct z_stream_s *m_inflate;
    wxFileOffset m_pos;
    DECLARE_NO_COPY_CLASS( wxZlibInputStream )
};

class wxZlibOutputStream: public wxFilterOutputStream {
  public:
    wxZlibOutputStream( wxOutputStream& stream, int level = -1, int flags = wxZLIB_ZLIB );
    wxZlibOutputStream( wxOutputStream *stream, int level = -1, int flags = wxZLIB_ZLIB );
    virtual ~wxZlibOutputStream() { Close(); }

    void Sync() { DoFlush( false ); }
    bool Close();
    wxFileOffset GetLength() const { return m_pos; }

    static bool CanHandleGZip();

  protected:
    size_t OnSysWrite( const void *buffer, size_t size );
    wxFileOffset OnSysTell() const { return m_pos; }

    virtual void DoFlush( bool final );

  private:
    void Init( int level, int flags );

  protected:
    size_t m_z_size;
    unsigned char *m_z_buffer;
    struct z_stream_s *m_deflate;
    wxFileOffset m_pos;

    DECLARE_NO_COPY_CLASS( wxZlibOutputStream )
};

class wxZlibClassFactory: public wxFilterClassFactory {
  public:
    wxZlibClassFactory();

    wxFilterInputStream *NewStream( wxInputStream& stream ) const
    { return new wxZlibInputStream( stream ); }
    wxFilterOutputStream *NewStream( wxOutputStream& stream ) const
    { return new wxZlibOutputStream( stream, -1 ); }
    wxFilterInputStream *NewStream( wxInputStream *stream ) const
    { return new wxZlibInputStream( stream ); }
    wxFilterOutputStream *NewStream( wxOutputStream *stream ) const
    { return new wxZlibOutputStream( stream, -1 ); }

    const wxChar * const *GetProtocols( wxStreamProtocolType type
                                        = wxSTREAM_PROTOCOL ) const;

  private:
    DECLARE_DYNAMIC_CLASS( wxZlibClassFactory )
};

class wxGzipClassFactory: public wxFilterClassFactory {
  public:
    wxGzipClassFactory();

    wxFilterInputStream *NewStream( wxInputStream& stream ) const
    { return new wxZlibInputStream( stream ); }
    wxFilterOutputStream *NewStream( wxOutputStream& stream ) const
    { return new wxZlibOutputStream( stream, -1, wxZLIB_GZIP ); }
    wxFilterInputStream *NewStream( wxInputStream *stream ) const
    { return new wxZlibInputStream( stream ); }
    wxFilterOutputStream *NewStream( wxOutputStream *stream ) const
    { return new wxZlibOutputStream( stream, -1, wxZLIB_GZIP ); }

    const wxChar * const *GetProtocols( wxStreamProtocolType type
                                        = wxSTREAM_PROTOCOL ) const;

  private:
    DECLARE_DYNAMIC_CLASS( wxGzipClassFactory )
};

#endif
// wxUSE_ZLIB && wxUSE_STREAMS

#endif
// _WX_WXZSTREAM_H__

